package top.zhangjianyong.tools.indicator.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import top.zhangjianyong.tools.entity.ETFData;
import top.zhangjianyong.tools.indicator.context.IndicatorContext;
import top.zhangjianyong.tools.indicator.factory.IndicatorFactory;
import top.zhangjianyong.tools.indicator.model.TechnicalIndicatorResult;
import top.zhangjianyong.tools.indicator.model.TechnicalIndicators;
import top.zhangjianyong.tools.indicator.strategy.TechnicalIndicator;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 技术指标计算工具类
 * 提供统一的计算入口，可以批量计算所有指标或指定指标
 *
 * @author zhangjianyong
 * @date 2024/01/01
 */
@Slf4j
@Component
public class IndicatorCalculator {

    @Autowired
    private IndicatorFactory indicatorFactory;

    /**
     * 计算单个技术指标
     *
     * @param indicatorName 指标名称
     * @param dataList      K线数据列表
     * @return 指标计算结果
     */
    public TechnicalIndicatorResult calculate(String indicatorName, List<ETFData> dataList) {
        return calculate(indicatorName, dataList, null);
    }

    /**
     * 计算单个技术指标（带参数）
     *
     * @param indicatorName 指标名称
     * @param dataList      K线数据列表
     * @param params        配置参数
     * @return 指标计算结果
     */
    public TechnicalIndicatorResult calculate(String indicatorName, List<ETFData> dataList, Map<String, Object> params) {
        TechnicalIndicator indicator = indicatorFactory.getIndicator(indicatorName);
        if (indicator == null) {
            log.warn("未找到指标计算器: {}", indicatorName);
            return TechnicalIndicatorResult.failure(indicatorName, "未找到指标计算器: " + indicatorName);
        }

        IndicatorContext context = new IndicatorContext(dataList, params);
        return indicator.calculate(context);
    }

    /**
     * 批量计算多个技术指标
     *
     * @param indicatorNames 指标名称列表
     * @param dataList       K线数据列表
     * @return 所有指标计算结果
     */
    public TechnicalIndicators calculateBatch(List<String> indicatorNames, List<ETFData> dataList) {
        return calculateBatch(indicatorNames, dataList, null);
    }

    /**
     * 批量计算多个技术指标（带参数）
     *
     * @param indicatorNames 指标名称列表
     * @param dataList       K线数据列表
     * @param params         配置参数
     * @return 所有指标计算结果
     */
    public TechnicalIndicators calculateBatch(List<String> indicatorNames, List<ETFData> dataList, Map<String, Object> params) {
        TechnicalIndicators results = new TechnicalIndicators();
        IndicatorContext context = new IndicatorContext(dataList, params);

        for (String indicatorName : indicatorNames) {
            TechnicalIndicator indicator = indicatorFactory.getIndicator(indicatorName);
            if (indicator == null) {
                log.warn("未找到指标计算器: {}", indicatorName);
                results.addResult(TechnicalIndicatorResult.failure(indicatorName, "未找到指标计算器"));
                continue;
            }

            try {
                TechnicalIndicatorResult result = indicator.calculate(context);
                results.addResult(result);
            } catch (Exception e) {
                log.error("计算指标{}时发生错误: {}", indicatorName, e.getMessage(), e);
                results.addResult(TechnicalIndicatorResult.failure(indicatorName, "计算失败: " + e.getMessage()));
            }
        }

        return results;
    }

    /**
     * 计算所有已注册的技术指标
     *
     * @param dataList K线数据列表
     * @return 所有指标计算结果
     */
    public TechnicalIndicators calculateAll(List<ETFData> dataList) {
        return calculateAll(dataList, null);
    }

    /**
     * 计算所有已注册的技术指标（带参数）
     *
     * @param dataList K线数据列表
     * @param params   配置参数
     * @return 所有指标计算结果
     */
    public TechnicalIndicators calculateAll(List<ETFData> dataList, Map<String, Object> params) {
        List<String> allIndicatorNames = new ArrayList<>(indicatorFactory.getAllIndicatorNames());
        return calculateBatch(allIndicatorNames, dataList, params);
    }

    /**
     * 计算核心指标（必须计算的指标）
     *
     * @param dataList K线数据列表
     * @return 核心指标计算结果
     */
    public TechnicalIndicators calculateCoreIndicators(List<ETFData> dataList) {
        List<String> coreIndicators = new ArrayList<>();
        coreIndicators.add("SMA");
        coreIndicators.add("EMA");
        coreIndicators.add("BIAS");
        coreIndicators.add("MACD");
        coreIndicators.add("RSI");
        coreIndicators.add("ATR");
        coreIndicators.add("BOLL");

        return calculateBatch(coreIndicators, dataList);
    }

    /**
     * 计算高质量指标
     *
     * @param dataList K线数据列表
     * @return 高质量指标计算结果
     */
    public TechnicalIndicators calculateHighQualityIndicators(List<ETFData> dataList) {
        List<String> highQualityIndicators = new ArrayList<>();
        highQualityIndicators.add("ADX");
        highQualityIndicators.add("OBV");
        highQualityIndicators.add("MFI");

        return calculateBatch(highQualityIndicators, dataList);
    }

    /**
     * 计算条件性指标（根据数据量选择性计算）
     *
     * @param dataList K线数据列表
     * @return 条件性指标计算结果
     */
    public TechnicalIndicators calculateConditionalIndicators(List<ETFData> dataList) {
        List<String> conditionalIndicators = new ArrayList<>();
        conditionalIndicators.add("CCI");
        conditionalIndicators.add("KDJ");
        conditionalIndicators.add("WILLIAMSR");
        conditionalIndicators.add("CMO");

        return calculateBatch(conditionalIndicators, dataList);
    }

    /**
     * 计算基础特征
     *
     * @param dataList K线数据列表
     * @return 基础特征计算结果
     */
    public TechnicalIndicators calculateBasicFeatures(List<ETFData> dataList) {
        List<String> basicFeatures = new ArrayList<>();
        basicFeatures.add("VOLUME");
        basicFeatures.add("MOMENTUM");
        basicFeatures.add("VOLATILITY");

        return calculateBatch(basicFeatures, dataList);
    }

    /**
     * 计算交互特征
     *
     * @param dataList K线数据列表
     * @return 交互特征计算结果
     */
    public TechnicalIndicators calculateInteractionFeatures(List<ETFData> dataList) {
        List<String> interactionFeatures = new ArrayList<>();
        interactionFeatures.add("MA_CROSS");
        interactionFeatures.add("PRICE_POSITION");
        interactionFeatures.add("VOLUME_PRICE_INTERACTION");
        interactionFeatures.add("INDICATOR_RATIO");

        return calculateBatch(interactionFeatures, dataList);
    }
}

